

from vtkmodules.vtkCommonTransforms import vtkTransform

from vtkmodules.vtkRenderingCore import (
    vtkActor,
    vtkPolyDataMapper,
    vtkShaderProperty,
    vtkActorCollection
)

from .Instance import InstanceActor

class Scene(vtkActorCollection):

    def __init__(self):
        self.name = "Scene"        
        self.transform = vtkTransform()
        self.instances = {}        
        # the nodes of current scene
        self.nodes = []
        #self.bboxes = []
        self.materials = []
        self.animations = []
        self.visible = True

    def AddNode(self, node):
        # store nodes?
        if node not in self.nodes:
            self.nodes.append(node)
        # node index
        #id = self.nodes.index(node)

        for mesh in node.meshes:
            for prim in mesh.primitives:
                self._add_instance(node, prim)            
        
        for child in node.children:
            self.AddNode(child)

    def _add_instance(self, node, prim):

        # group by materials...
        mtl = self.materials[prim.material]
        if mtl not in self.instances:
            actor = InstanceActor() 
            actor.SetUserTransform(self.transform)             
            actor.SetProperty(mtl)
            actor.SetShaderProperty(mtl.GetShaderProperty())
            # add a flag for selection...
            actor.scene = self

            self.instances[mtl] = actor   
            self.AddItem(actor)  
            
            if False:
                bbox = BBoxActor(actor)
                bbox.GetProperty().SetColor(0, 0, 1)
                self.actors.append(bbox) 
                self.bboxes.append(bbox)                

            if False:
                actor0 = vtkActor()
                actor0.SetUserTransform(node.worldTransform)
                mapper0 = vtkPolyDataMapper()
                mapper0.SetInputData(prim.GetPolyData())
                actor0.SetMapper(mapper0)

                bbox = BBoxActor(actor0)
                bbox.GetProperty().SetColor(1, 0, 0)
                self.actors.append(bbox) 
                self.bboxes.append(bbox)

        self.instances[mtl].AddPrimitive(prim, node)
        
    def Update(self):
        # update all instances
        for mtl in self.instances:
            instance = self.instances[mtl] 
            instance.Update()
        #for bbox in self.bboxes:
        #    bbox.Update()     

    def ResetAnimation(self):
        # TODO: fix...
        for node in self.nodes:
            for mesh in node.meshes:
                for prim in mesh.primitives:
                    prim.ResetSkinTransform()
        self.Update()

    # set visibility for all nodes
    def SetVisible(self, v):
        self.visible = v
        for node in self.nodes:
            node.SetVisible(v)

    def GetNumberOfAnimations(self):
        return len(self.animations)

    def PlayAnimation(self, idx):
        if idx >= 0 and idx < len(self.animations): 
            self.animations[idx].play = True
            print("Enable Animation:", self.animations[idx].name) 

    def StopAnimation(self, idx):
        if idx >= 0 and idx < len(self.animations): 
            self.animations[idx].play = False
            print("Enable Animation:", self.animations[idx].name)             
    

    def UpdateAnimation(self, time, loop=True):
        def update(animation, time, loop):
            t0 = animation.GetStartTime()
            t1 = animation.GetEndTime()
            duration = t1 - t0
            while loop and time > t1:
                time -= duration
            animation.SetAnimationTime(time)

        sceneUpdated = False
        #if self.activeAnimation:
        for animation in self.animations:
            if animation.play:
                update(animation, time, loop)  
                sceneUpdated = True

        if sceneUpdated:          
            self.Update()
        return sceneUpdated
    
    def GetNodesByExtras(self, key, value):
        nodes = []
        for node in self.nodes:
            if key in node.extras:
                if node.extras[key] == value:
                    nodes.append(node)
        return nodes


